using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using Object = UnityEngine.Object;

namespace HyuFrameWork
{
    public class ABService : ServiceBase
    {
        //AB包管理器 目的是
        //让外部更方便的进行资源加载

        //主包
        private AssetBundle mainAB;

        //依赖包获取用的配置文件
        private AssetBundleManifest manifest;

        //AB包不能够重复加载 重复加载会报错
        //字典 用字典来存储 加载过的AB包 
        private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();

        /// <summary>
        /// 这个AB包存放路径 方便修改
        /// </summary>
        private string PathUrl
        {
            get { return Application.streamingAssetsPath + "/"; }
        }

        /// <summary>
        /// 主包名 方便修改
        /// </summary>
        private string MainABName
        {
            get
            {
#if UNITY_IOS
                return "IOS";
#elif UNITY_ANDROID
                return "Android";
#else
                return "StandaloneWindows";
#endif
            }
        }


        #region 加载AB包 同步&异步

        public AssetBundle LoadAB(string abName)
        {
            if (abDic.TryGetValue(abName, out AssetBundle ab))
                return ab;
            
            //加载AB包
            if (mainAB == null)
            {
                mainAB = AssetBundle.LoadFromFile(PathUrl + MainABName);
                manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            }

            //我们获取依赖包相关信息
            string[] strs = manifest.GetAllDependencies(abName);
            for (int i = 0; i < strs.Length; i++)
            {
                //判断包是否加载过
                if (!abDic.ContainsKey(strs[i]))
                {
                    ab = AssetBundle.LoadFromFile(PathUrl + strs[i]);
                    abDic.Add(strs[i], ab);
                }
            }

            //加载资源来源包
            //如果没有加载过 再加载
            if (!abDic.TryGetValue(abName,out ab))
            {
                ab = AssetBundle.LoadFromFile(PathUrl + abName);
                abDic.Add(abName, ab);
            }
            return ab;
        }

        public void LoadABAsync(string abName,UnityAction<float> progCB, UnityAction<AssetBundle> succCB)
        {
            //加载AB包
            if (mainAB == null)
            {
                mainAB = AssetBundle.LoadFromFile(PathUrl + MainABName);
                manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            }

            //我们获取依赖包相关信息
            AssetBundle ab = null;
            string[] strs = manifest.GetAllDependencies(abName);
            for (int i = 0; i < strs.Length; i++)
            {
                //判断包是否加载过
                if (!abDic.ContainsKey(strs[i]))
                {
                    ab = AssetBundle.LoadFromFile(PathUrl + strs[i]);
                    abDic.Add(strs[i], ab);
                }
            }

            //加载资源来源包
            //如果没有加载过 再加载
            if (abDic.TryGetValue(abName,out ab))
            {
                succCB?.Invoke(ab);
            }
            else
            {
                StartCoroutine(ReallyLoadABAsync(abName,progCB,succCB));
            }
        }

        IEnumerator ReallyLoadABAsync(string abName,UnityAction<float> progCB, UnityAction<AssetBundle> succCB)
        {
            AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(PathUrl + abName);
            if (progCB != null)
            {
                while (true)
                {
                    var progress = abcr.progress;
                    progCB.Invoke(progress);
                    if (abcr.isDone)
                    {
                        abDic.Add(abName, abcr.assetBundle);
                        succCB?.Invoke(abcr.assetBundle);
                        break;
                    }
                    yield return null;
                }
            }
            else
            {
                yield return abcr;
                abDic.Add(abName, abcr.assetBundle);
                succCB?.Invoke(abcr.assetBundle);
            }
        }

        #endregion
        
        #region 泛型加载

        //同步加载 根据泛型指定类型
        public T LoadRes<T>(string abName, string resName) where T : Object
        {
            //加载AB包
            T obj = LoadAB(abName).LoadAsset<T>(resName);
            return obj;
        }

        public T[] LoadAllRes<T>(string abName) where T : Object
        {
            return LoadAB(abName).LoadAllAssets<T>();
        }

        //根据泛型 异步加载资源
        public void LoadResAsync<T>(string abName, string resName,
            UnityAction<float> progAbCB, UnityAction<AssetBundle> succAbCB,
            UnityAction<float> progCB, UnityAction<T> succCB) where T : Object
        {
            StartCoroutine(ReallyLoadResAsync<T>(abName, resName, progAbCB,succAbCB,progCB,succCB));
        }

        private IEnumerator ReallyLoadResAsync<T>(string abName, string resName, 
            UnityAction<float> progAbCB, UnityAction<AssetBundle> succAbCB,
            UnityAction<float> progCB, UnityAction<T> succCB)
            where T : Object
        {
            //加载AB包
            LoadABAsync(abName,progAbCB,succAbCB);
            AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(resName);
            if (progCB != null)
            {
                while (true)
                {
                    var progress = abr.progress;
                    progCB.Invoke(progress);
                    if (abr.isDone)
                    {
                        succCB?.Invoke(abr.asset as T);
                        break;
                    }
                    yield return null;
                }
            }
            else
            {
                yield return abr;
                succCB?.Invoke(abr.asset as T);
            }
        }

        #endregion

        #region Object加载

        //同步加载 不指定类型
        public Object LoadRes(string abName, string resName)
        {
            Object obj = LoadAB(abName).LoadAsset(resName);
            return obj;
        }

        
        public void LoadResAsync(string abName, string resName,
            UnityAction<float> progAbCB, UnityAction<AssetBundle> succAbCB,
            UnityAction<float> procCB, UnityAction<Object> succCB)
        {
            StartCoroutine(ReallyLoadResAsync(abName, resName,progAbCB,succAbCB, procCB,succCB));
        }

        private IEnumerator ReallyLoadResAsync(string abName, string resName, 
            UnityAction<float> progAbCB, UnityAction<AssetBundle> succAbCB,
            UnityAction<float> progCB, UnityAction<Object> succCB)
        {
            //加载AB包
            LoadABAsync(abName,progAbCB,succAbCB);
            AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName);
            if (progCB != null)
            {
                while (true)
                {
                    var progress = abr.progress;
                    progCB.Invoke(progress);
                    if (abr.isDone)
                    {
                        succCB?.Invoke(abr.asset);
                        break;
                    }
                    yield return null;
                }
            }
            else
            {
                yield return abr;
                succCB?.Invoke(abr.asset);
            }
        }
        #endregion

        #region 根据Type加载 Lua

        //同步加载 根据type指定类型
        public Object LoadRes(string abName, string resName, System.Type type)
        {
            Object obj = LoadAB(abName).LoadAsset(resName, type);
            return obj;
        }
        
        public void LoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
        {
            StartCoroutine(ReallyLoadResAsync(abName, resName, type, callBack));
        }

        private IEnumerator ReallyLoadResAsync(string abName, string resName, System.Type type,
            UnityAction<Object> callBack)
        {
            AssetBundleRequest abr = LoadAB(abName).LoadAssetAsync(resName, type);
            yield return abr;
            //异步加载结束后 通过委托 传递给外部 外部来使用
            callBack(abr.asset);
        }
        
        #endregion
        
        //单个包卸载
        public void UnLoad(string abName , bool bAll = false)
        {
            if (abDic.ContainsKey(abName))
            {
                abDic[abName].Unload(bAll);
                abDic.Remove(abName);
            }
        }
        
        //所有包的卸载
        public void ClearAB()
        {
            AssetBundle.UnloadAllAssetBundles(false);
            abDic.Clear();
            mainAB = null;
            manifest = null;
        }

        private void OnDestroy()
        {
            ClearAB();
        }

    }
}